// AudioOutDS.cpp: implementation of the AudioOutDS class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include <streams.h>
#include "AudioNullSource.h"
#include "AudioOutGrabber.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
#pragma comment(lib,"Strmiids.lib") 
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CAudioOutGrabber::CAudioOutGrabber()
{
	m_pGraph = NULL;
	m_pMediaControl = NULL;
	m_pMediaEvent=NULL;
	m_pNullSourceClass=NULL;
	m_pNullSource = NULL;
	m_pNullSourcePin = NULL;
	m_bConnected=FALSE;
}

CAudioOutGrabber::~CAudioOutGrabber()
{
	CloseRender();
	//CoUninitialize();
}

HRESULT CAudioOutGrabber::AddToRot(IUnknown *pUnKnown,DWORD * pdwRegister)
{
	CComPtr<IMoniker> pMoniker=NULL;
	CComPtr<IRunningObjectTable> pROT=NULL;
	if (FAILED(GetRunningObjectTable(0,&pROT)))
	{
		return E_FAIL;
	}
	WCHAR wsz[256];
	wsprintfW(wsz,L"FilterGrap %08x pid %08x",(DWORD_PTR) pUnKnown,GetCurrentProcessId());
	HRESULT hr= CreateItemMoniker(L"!",wsz,&pMoniker);
	if (SUCCEEDED(hr))
	{
		hr=pROT->Register(ROTFLAGS_REGISTRATIONKEEPSALIVE,pUnKnown,pMoniker,pdwRegister);
		pMoniker=NULL;
	}
	pROT=NULL;
	return hr;

}
void CAudioOutGrabber::RemoveFromRot(DWORD pdwRegister)
{
	CComPtr<IRunningObjectTable> pROT=NULL;
	if (SUCCEEDED(GetRunningObjectTable(0,&pROT)))
	{
		pROT->Revoke(pdwRegister);
		pROT=NULL;
	}
}
BOOL CAudioOutGrabber::OpenRender()
{
	HRESULT hr = S_OK;
	
	//CoInitialize(NULL);
	hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC,
		IID_IGraphBuilder, (void **)&m_pGraph);
#ifdef _DEBUG
	hr=AddToRot(m_pGraph.p,&m_dwRegister);
#endif // _DEBUG
	hr = m_pGraph->QueryInterface(IID_IMediaControl, (void **) &m_pMediaControl);
	hr = m_pGraph->QueryInterface(IID_IMediaEvent, (void **) &m_pMediaEvent);	
	m_pNullSourceClass=(CNullSource *)CNullSource::CreateInstance(NULL,&hr);
	m_pNullSource=m_pNullSourceClass;
	hr = m_pGraph->AddFilter(m_pNullSource, L"NullSource");

//	BindFilter(&m_pDeviceFilter);
//	m_pGraph->AddFilter(m_pDeviceFilter, NULL);

	CComPtr<IEnumPins> pEnum;
	m_pNullSource->EnumPins(&pEnum);
	hr = pEnum->Reset();
	hr = pEnum->Next(1, &m_pNullSourcePin, NULL); 

	//m_pDeviceFilter->EnumPins(&pEnum);
	//hr = pEnum->Reset();
	//hr = pEnum->Next(1, &m_pDeviceInput, NULL); 

	m_pGraph->Render(m_pNullSourcePin);
	//hr = m_pGraph->Connect(m_pNullSourcePin, m_pDeviceInput);
	m_pMediaControl->Run();
	m_bConnected=TRUE;
	return true;
}
BOOL CAudioOutGrabber::CloseRender()
{
	if(m_bConnected)
		m_pMediaControl->Stop();

#ifdef _DEBUG
	RemoveFromRot(m_dwRegister);
#endif // _DEBUG

	m_pMediaControl = NULL;
	m_pMediaEvent=NULL;
	m_pNullSourceClass=NULL;
	m_pNullSource = NULL;
	m_pNullSourcePin = NULL;
//	m_pDeviceFilter =NULL;
	m_pGraph = NULL;

	m_bConnected=FALSE;
	return true;
}
BOOL CAudioOutGrabber::PushBuffer(BYTE * pBuffer,long nSize)
{
	if (m_bConnected)
		m_pNullSourceClass->PushBuffer(pBuffer,nSize);
	return true;
}


bool CAudioOutGrabber::BindFilter(IBaseFilter **pFilter)
{
	// enumerate all audio capture devices
	CComPtr<ICreateDevEnum> pCreateDevEnum;
	HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
		IID_ICreateDevEnum, (void**)&pCreateDevEnum);
	if (hr != NOERROR)
	{
		return false;
	}

	CComPtr<IEnumMoniker> pEm;
	hr = pCreateDevEnum->CreateClassEnumerator(CLSID_AudioRendererCategory,
		&pEm, 0);
	if (hr != NOERROR) 
	{
		return false;
	}

	pEm->Reset();
	ULONG cFetched;
	IMoniker *pM;
	char   szPropertyBag[64];  
	while((pEm->Next(1, &pM, &cFetched)==S_OK))
	{
		IPropertyBag *pBag;
		hr = pM->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pBag);
		if(SUCCEEDED(hr)) 
		{
			VARIANT var;
			var.vt = VT_BSTR;
			hr = pBag->Read(L"Description", &var, NULL);
			if (hr==NOERROR)
			{
				int   nLen   =   wcslen(var.bstrVal)+1;
				WideCharToMultiByte(CP_ACP,0,var.bstrVal,nLen,szPropertyBag,2*nLen,NULL,NULL); 
				TRACE("Description :%s\r\n",szPropertyBag);
				SysFreeString(var.bstrVal);
			}
			hr = pBag->Read(L"FriendlyName", &var, NULL);
			if (hr==NOERROR)
			{
				int   nLen   =   wcslen(var.bstrVal)+1;
				WideCharToMultiByte(CP_ACP,0,var.bstrVal,nLen,szPropertyBag,2*nLen,NULL,NULL); 
				TRACE("FriendlyName :%s\r\n",szPropertyBag);
				SysFreeString(var.bstrVal);
			}
			pBag->Release();
		}
		pM->Release();
	}
	pEm->Reset();
	if (pEm->Next(1, &pM, &cFetched)==S_OK)
	{
		IPropertyBag *pBag;
		hr = pM->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pBag);
		if(SUCCEEDED(hr)) 
		{
			VARIANT var;
			var.vt = VT_BSTR;
			hr = pBag->Read(L"Description", &var, 0);
			hr = pBag->Read(L"FriendlyName", &var, NULL);
			if (hr==NOERROR)
			{
				int   nLen   =   wcslen(var.bstrVal)+1;
				WideCharToMultiByte(CP_ACP,0,var.bstrVal,nLen,szPropertyBag,2*nLen,NULL,NULL); 
				TRACE("%s\r\n",szPropertyBag);
				SysFreeString(var.bstrVal);
			}
			if (hr == NOERROR) 
			{
				pM->BindToObject(0, 0, IID_IBaseFilter, (void**)pFilter);
			}
			pBag->Release();
		}
		pM->Release();
	}

	pCreateDevEnum = NULL;
	return true;
}